package org.firebug.spring.boot.swagger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
import sun.awt.CharsetString;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public final class HttpUtils {
    private static Logger logger = LoggerFactory.getLogger("third");
    private HttpUtils() {}

    private static String serialize(Map<?, ?> param){
        StringBuilder params = new StringBuilder();
        for (Entry<?, ?> entry : param.entrySet()) {
            params.append(entry.getKey() + "=" + entry.getValue() + "&");
        }
        params.deleteCharAt(params.length() - 1);
        return params.toString();
    }

    public static String get(String url) throws IOException {
        return get(url, Charset.defaultCharset());
    }
    public static String get(String url, Map<?, ?> inputs) throws IOException {
        return get(url, inputs, Charset.defaultCharset());
    }
    public static String get(String url, Map<?, ?> inputs, Charset charset) throws IOException {
        String params = serialize(inputs);
        return get(url + "?" + params, charset);
    }
    public static String get(String url, Charset charset) throws IOException {
        logger.info("GET request: {}", url);
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setConnectTimeout(6000);
            connection.setReadTimeout(6000);
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Cache-Control", "no-cache");
            connection.setRequestProperty("Connection", "Keep-Alive");
//            connection.setRequestProperty("Accept", "application/json");
            connection.setDoOutput(false);
            connection.setDoInput(true);
            //
            String response = StreamUtils.copyToString(connection.getInputStream(), charset);
            logger.info("GET response: {}", response);
            return response;
        } catch (IOException e) {
            logger.error(url, e);
            throw e;
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    public static String post(String url, Map<?, ?> inputs) throws IOException {
        return post(url, inputs, Charset.defaultCharset());
    }
    public static String post(String url, Map<?, ?> inputs, Charset charset) throws IOException {
        String body = serialize(inputs);
        return post(url, body, charset, "application/x-www-form-urlencoded");
    }
    public static String post(String url, String body) throws IOException {
        return post(url, body, Charset.defaultCharset());
    }
    public static String post(String url, String body, Charset charset) throws IOException {
        return post(url, body, charset, "application/x-www-form-urlencoded");
    }
    public static String postJson(String url, String json) throws IOException {
        return postJson(url, json, Charset.defaultCharset());
    }
    public static String postJson(String url, String json, Charset charset) throws IOException {
        String contentType = "application/json; charset=" + charset.toString();
        return post(url, json, charset, contentType);
    }
    public static String post(String url, String body, String contentType) throws IOException {
        return post(url, body, Charset.defaultCharset(), contentType);
    }
    public static String post(String url, String body, Charset charset, String contentType) throws IOException {
        HttpURLConnection connection = null;
        logger.info("POST request: {} {}", url, body);
        try {
            connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setConnectTimeout(6000);
            connection.setReadTimeout(6000);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Cache-Control", "no-cache");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", contentType);
            connection.setDoOutput(true);
            connection.setDoInput(true);
            StreamUtils.copy(body, charset, connection.getOutputStream());
            String response = StreamUtils.copyToString(connection.getInputStream(), charset);
            logger.info("POST response: {}", response);
            return response;
        } catch (IOException e) {
            logger.error(url, e);
            throw e;
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    public static String postMultipartFormData(String url, Map<String, File[]> form) throws IOException {
        HttpURLConnection connection = null;
        logger.info("POST multipart/form-data request: {}", url);
        String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
        try {
            connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestProperty("Cache-Control", "no-cache");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            OutputStream os = connection.getOutputStream();
            for(Entry<String, File[]> entry : form.entrySet()) {
                String key = entry.getKey();
                File[] files = entry.getValue();
                for(File file : files) {
                    outputFile(boundary, os, key, file);
                }
            }
            outputFoot(boundary, os);
            String response = StreamUtils.copyToString(connection.getInputStream(), Charset.defaultCharset());
            logger.info("POST multipart/form-data response: {}", response);
            return response;
        } catch (IOException e) {
            logger.error(url, e);
            throw e;
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
    private static void outputInput(String boundary, OutputStream os, String name, String value) throws IOException {
        os.write(("--" + boundary + "\r\n").getBytes());
        os.write(("Content-Disposition: form-data; name=\"" + name + "\"\r\n").getBytes());
        os.write("\r\n".getBytes());
        os.write(value.getBytes());
        os.write("\r\n".getBytes());
        os.flush();
    }
    private static void outputFile(String boundary, OutputStream os, String name, File value) throws IOException {
        String filename = value.getName();
        InputStream is = new FileInputStream(value);
        outputStream(boundary, os, name, filename, is);
        is.close();
    }
    private static void outputStream(String boundary, OutputStream os, String name, String filename, InputStream is) throws IOException {
        os.write(("--" + boundary + "\r\n").getBytes());
        os.write(("Content-Disposition: form-data;name=\"" + name + "\"; filename=\"" + filename + "\"\r\n").getBytes());
        os.write(("Content-Type: application/octet-stream\r\n").getBytes());
        os.write("\r\n".getBytes());
        StreamUtils.copy(is, os);
        os.write("\r\n".getBytes());
        os.flush();
    }
    private static void outputFoot(String boundary, OutputStream os) throws IOException {
        os.write(("--" + boundary + "--" + "\r\n").getBytes());
        os.flush();
    }

    public static void main(String[] args) throws Exception {
//        String url = "http://127.0.0.1:8080/file/upload";
        String url = "http://localhost:8080/message/oss/save";
        Map<String, File[]> form = new HashMap<>();
        form.put("file", new File[]{new File("d://cat.txt")});
//        form.put("images", new File[]{new File("d://狮子.gif"), new File("d://cat.jpg")});
        postMultipartFormData(url, form);
    }
}
